#include "cppTutorPolymorphism.h"

#include <iostream>

using namespace std;

int CcppTutorPolyBase :: m_nPolyBaseConstructorCount = 0;

CcppTutorPolyBase :: CcppTutorPolyBase () : m_nPolyBasePriValue (0), m_nPolyBasePubValue (0), m_nPolyBaseProValue (0)
{
    cout << "ENTER : CcppTutorPolyBase :: CcppTutorPolyBase ()" << endl;
    m_npPolyBasePriValue = new int;
    m_nPolyBaseConstructorCount ++;
    cout << "constructer [" << m_nPolyBaseConstructorCount << "]" << endl;
    cout << "EXIT  : CcppTutorPolyBase :: CcppTutorPolyBase ()" << endl;
}

CcppTutorPolyBase :: CcppTutorPolyBase (std :: string strName) : m_nPolyBasePriValue (0), m_nPolyBasePubValue (0), m_nPolyBaseProValue (0), m_strName (strName)
{
    cout << "ENTER : CcppTutorPolyBase :: CcppTutorPolyBase (std :: string)" << endl;
    m_npPolyBasePriValue = new int;
    cout << "EXIT  : CcppTutorPolyBase :: CcppTutorPolyBase (std :: string)" << endl;
}

CcppTutorPolyBase :: ~CcppTutorPolyBase ()
{
    cout << "ENTER : CcppTutorPolyBase :: ~CcppTutorPolyBase ()" << endl;
    delete m_npPolyBasePriValue;
    m_nPolyBaseConstructorCount --;
    cout << "destructor [" << m_nPolyBaseConstructorCount << "]" << endl;
    cout << "EXIT  : CcppTutorPolyBase :: ~CcppTutorPolyBase ()" << endl;
}

string CcppTutorPolyBase :: m_PolyWhoAmI()
{
	return "base class";
}

const char* CcppTutorPolyBase :: Speak() 
{ 
    return "???"; 
}

/***********************/
/*** derived_1 class ***/
/***********************/

CcppTutorPolyDerived_1 :: CcppTutorPolyDerived_1 () : m_nPolyDerived_1_PriValue (10), m_nPolyDerived_1_PubValue (10), m_nPolyDerived_1_ProValue (10)
{
    cout << "ENTER : CcppTutorPolyDerived_1 :: CcppTutorPolyDerived_1 ()" << endl;
    m_npPolyDerived_1_PriValue = new int;
    cout << "EXIT  : CcppTutorPolyDerived_1 :: CcppTutorPolyDerived_1 ()" << endl;
}

CcppTutorPolyDerived_1 :: CcppTutorPolyDerived_1 (std :: string strName) : m_nPolyDerived_1_PriValue (10), m_nPolyDerived_1_PubValue (10), m_nPolyDerived_1_ProValue (10), CcppTutorPolyBase (strName)
{
    cout << "ENTER : CcppTutorPolyDerived_1 :: CcppTutorPolyDerived_1 (std :: string)" << endl;
    m_npPolyDerived_1_PriValue = new int;
    cout << "EXIT  : CcppTutorPolyDerived_1 :: CcppTutorPolyDerived_1 (std :: string)" << endl;
}

CcppTutorPolyDerived_1 :: ~CcppTutorPolyDerived_1 ()
{
    cout << "ENTER : CcppTutorPolyDerived_1 :: ~CcppTutorPolyDerived_1 ()" << endl;
    delete m_npPolyDerived_1_PriValue;
    cout << "EXIT  : CcppTutorPolyDerived_1 :: ~CcppTutorPolyDerived_1 ()" << endl;
}

const char* CcppTutorPolyDerived_1 :: Speak() 
{ 
    return "derived_1"; 
}

/***********************/
/*** derived_2 class ***/
/***********************/

CcppTutorPolyDerived_2 :: CcppTutorPolyDerived_2 () : m_nPolyDerived_2_PriValue (10), m_nPolyDerived_2_PubValue (10), m_nPolyDerived_2_ProValue (10)
{
    cout << "ENTER : CcppTutorPolyDerived_2 :: CcppTutorPolyDerived_2 ()" << endl;
    cout << "EXIT  : CcppTutorPolyDerived_2 :: CcppTutorPolyDerived_2 ()" << endl;
}

CcppTutorPolyDerived_2 :: CcppTutorPolyDerived_2 (std :: string strName) : m_nPolyDerived_2_PriValue (10), m_nPolyDerived_2_PubValue (10), m_nPolyDerived_2_ProValue (10), CcppTutorPolyBase (strName)
{
    cout << "ENTER : CcppTutorPolyDerived_2 :: CcppTutorPolyDerived_2 (std :: string)" << endl;
    cout << "EXIT  : CcppTutorPolyDerived_2 :: CcppTutorPolyDerived_2 (std :: string)" << endl;
}

CcppTutorPolyDerived_2 :: ~CcppTutorPolyDerived_2 ()
{
    cout << "ENTER : CcppTutorPolyDerived_2 :: ~CcppTutorPolyDerived_2 ()" << endl;
    cout << "EXIT  : CcppTutorPolyDerived_2 :: ~CcppTutorPolyDerived_2 ()" << endl;
}

const char* CcppTutorPolyDerived_2 :: Speak() 
{ 
    return "derived_2"; 
}

// global function for all the three classes
void _Report (CcppTutorPolyBase &getReport)
{
    cout <<  getReport.m_PolyWhoAmI() << " says " << getReport.Speak() << " received !!!"<< endl;
}

#ifdef SIZE_OF_CLASS_WITH_VIRTUAL
void CcppTutorNoVirtual :: x() const 
{
}

#ifdef ONE_VIRTUAL
void CcppTutorOneVirtual :: x() const 
{
}
#endif //ONE_VIRTUAL

#ifdef TWO_VIRTUAL
void CcppTutorTwoVirtuals :: x() const 
{
}

int CcppTutorTwoVirtuals :: i() const 
{
}
#endif //TWO_VIRTUAL
#endif //SIZE_OF_CLASS_WITH_VIRTUAL
